/*
    性能测试
        1.N 条日志输出耗时
        2.每秒输出日志数
        3.每秒输出日志大小
*/

#include "../logsystem/log.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>
#include <memory>
#include <algorithm>

// 性能测试函数
void Bench(const std::string &name, size_t threadNum, size_t logNum, size_t logLen)
{
    std::cout << "====================================" << std::endl;
    std::cout << "测试开始" << std::endl;
    std::cout << "当前日志器: " << name << std::endl;
    std::cout << "待工作线程数: " << threadNum << " 个" << std::endl;
    std::cout << "待写入日志数: " << logNum << " 条" << std::endl;
    std::cout << "单条日志大小: " << logLen << " Byte" << std::endl;

    // 首先判断日志器是否存在
    if(!Yohifo::LoggerManage::GetInstance().Find(name))
        std::cerr << "当前日志器: " << name << "不存在，使用默认 [root日志器]" << std::endl;

    // 1、获取日志器
    Yohifo::Logger::ptr logger = Yohifo::LoggerManage::GetInstance().GetLogger(name);

    // 2、组织指定长度的消息字符串
    std::string msg(logLen - 1, 'X'); // 留出一个字符给 换行符

    // 3、创建一批线程，执行任务为：输出指定数量的日志
    std::vector<std::thread> threads;

    // 计算出每一个线程需要平均写的日志数
    size_t num = (logNum / threadNum);
    size_t remainder = (logNum % threadNum); // 余数，随机交给一个线程，多处理一点
    double maxTime = 0; // 所有线程中，耗时最长的，就是总耗时

    for(size_t i = 0; i < threadNum; i++)
    {
        // 创建线程
        // 细节：
        //      1、涉及改变的参数传值，并且可以使用 mutable 取消常性
        //      2、使用 emplace 系列，减少拷贝次数
        threads.emplace_back([&, num, i]()mutable->void
                             {
                                // 4、线程内部开始计时
                                auto begin = std::chrono::high_resolution_clock::now();
                                // 5、循环写日志
                                if(i == 0)
                                    num += remainder;

                                for(size_t j = 0; j < num; j++)
                                    logger->FATAL("%s", msg.c_str());

                                // 6、线程内部结束计时
                                auto end = std::chrono::high_resolution_clock::now();
                                std::chrono::duration<double> cost = (end - begin);
                                double time = cost.count();

                                if(time > maxTime)
                                    maxTime = time;

                                std::cout << "线程 " << i << "\t输出 " << num 
                                          << " 条日志消息，耗时: " << time << " 秒" << std::endl;
                             });
    }

    // 7、等待次线程退出
    for(int i = 0; i < threadNum; i++)
        threads[i].join();

    // 8、计算总耗时、每秒输出日志数、每秒输出日志大小
    size_t outSec = (logNum / maxTime);
    size_t outSize = (logNum * logLen) / (maxTime * 1024);

    // 9、输出结果
    std::cout << "\t总耗时: " << maxTime << " 秒" << std::endl;
    std::cout << "\t平均每秒写入日志: " << outSec << " 条" << std::endl;
    std::cout << "\t平均每秒输出日志大小: " << outSize << " KB" << std::endl;

    std::cout << "测试结束" << std::endl;
    std::cout << "====================================" << std::endl;
}

// 同步日志器测试
void SyncTest()
{
    std::shared_ptr<Yohifo::LoggerBuilder> builder(new Yohifo::GlobalLoggerBuilder);
    builder->BuildLoggerType(Yohifo::LoggerType::LOGGER_SYNC);
    builder->BuildLoggerName("SyncLogger");
    builder->BuildLoggerLimit(Yohifo::LogLevel::Value::DEBUG);
    builder->BuildFormat("%m%n");
    builder->BulidSink<Yohifo::FileSink>("./Logfile/Test.log");
    builder->Build();

    Bench("SyncLogger", 33, 1000000, 100);
}

// 异步日志器测试
void AsyncTest()
{
    std::shared_ptr<Yohifo::LoggerBuilder> builder(new Yohifo::GlobalLoggerBuilder);
    builder->BuildLoggerType(Yohifo::LoggerType::LOGGER_ASYNC);
    builder->BuildAsyncType(Yohifo::AsyncType::ASYNC_UNSAFE); // 测试性能需要调整为 非安全模式
    builder->BuildLoggerName("AsyncLogger");
    builder->BuildLoggerLimit(Yohifo::LogLevel::Value::DEBUG);
    builder->BuildFormat("%m%n");
    builder->BulidSink<Yohifo::FileSink>("./Logfile/Test.log");
    builder->Build();

    Bench("AsyncLogger", 50, 10000000, 100);
}

int main()
{
    // SyncTest();
    AsyncTest();
    return 0;
}